﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FA.Library.Util;
using FA.Library.Sim;
using FA.Library.Sim.Events;
using FA.Library.Plugin;
using System.Collections.ObjectModel;
using FA.FlightAttendant.Plugin;
using FA.Library.Sim.Aircraft;

namespace FA.FlightAttendant.Host
{
    public class SimStateManager
    {
        public event SimAircraftModelChangedEvent OnSimAircraftModelChanged;
        public event SimMessageEvent OnSimMessage;
        public event SimExceptionEvent OnSimException;

        /// <summary>
        /// Flag indicating if the aircraft models are currently updating, in
        /// which case ignore their change events.
        /// </summary>
        private bool _currentlyUpdatingAircraftModels = false;

        /// <summary>
        /// The aircraft model which the state manager must ensure that all registered
        /// simulators are using.
        /// </summary>
        public AircraftModel CommonAircraftModel
        {
            get { return _globalAircraftModel; }
            private set
            {
                if (value != _globalAircraftModel)
                {
                    _globalAircraftModel = value;
                }
            }
        }
        private AircraftModel _globalAircraftModel = null;

        // The simulators
        private ObservableCollection<Simulator> _simulators;

        // The sim event queue contains all incoming events from simulators
        private TaskQueue<SimEvent> _simEventQueue;

        public SimStateManager(ObservableCollection<Simulator> simulators)
        {
            _simulators = simulators;
            _simEventQueue = new TaskQueue<SimEvent>(processSimEvent);
        }

        /// <summary>
        /// Register event handlers for a simulator such that they are processed in the event queue.
        /// </summary>
        /// <p name="plugin"></p>
        public void RegisterSimulatorEvents(Simulator sim)
        {
            sim.Plugin.OnSimAircraftModelChangedEvent += (s, p) => { _simEventQueue.EnqueueItem(new SimEvent(s, SimEventType.AircraftModelChanged, p)); };
            sim.Plugin.OnSimMessageEvent += (s, p) => { _simEventQueue.EnqueueItem(new SimEvent(s, SimEventType.Message)); };
            sim.Plugin.OnSimExceptionEvent += (s, p) => { _simEventQueue.EnqueueItem(new SimEvent(s, SimEventType.Exception, p)); };
        }

        /// <summary>
        /// Process a sim event.
        /// </summary>
        /// <p name="simEvent"></p>
        private void processSimEvent(SimEvent e)
        {
            switch (e.Type)
            {
                case SimEventType.AircraftModelChanged:
                    processAircraftModelChanged(e.Sender, e.Params as SimAircraftModelChangedEventArgs);
                    if (OnSimAircraftModelChanged != null)
                        OnSimAircraftModelChanged(e.Sender, e.Params as SimAircraftModelChangedEventArgs);
                    break;
                case SimEventType.Message:
                    processMessage(e.Sender, e.Params as SimMessageEventArgs);
                    if (OnSimMessage != null)
                        OnSimMessage(e.Sender, e.Params as SimMessageEventArgs);
                    break;
                case SimEventType.Exception:
                    processException(e.Sender, e.Params as SimExceptionEventArgs);
                    if (OnSimException != null)
                        OnSimException(e.Sender, e.Params as SimExceptionEventArgs);
                    break;
            }
        }

        /// <summary>
        /// Process an model change received from a simulator.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void processAircraftModelChanged(object sender, SimAircraftModelChangedEventArgs args)
        {
            foreach (Simulator simulator in _simulators)
            {
                if (simulator.Plugin != sender)
                    simulator.UpdateAircraftModel(args.AircraftModel, true);
            }
        }

        /// <summary>
        /// Process a message received from a simulator.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void processMessage(object sender, SimMessageEventArgs args)
        {
            // TODO
            throw new NotImplementedException();
        }

        /// <summary>
        /// Process an exception received from a simulator.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void processException(object sender, SimExceptionEventArgs args)
        {
            // TODO
            throw new NotImplementedException();
        }
    }
}
